package experiments;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.io.*;
import java.lang.*;
import matlabcontrol.*;

import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import java.util.*;
//import system.Application;
import system.*;
import Machine.*;
//import system.SearchSpace;
//import system.ShareModel;
//import system.ShareModelMinShareOptimize;


public class singleLevelConverge extends Thread{
	static Metric[] metrics;
	//static int noOfHosts = 3;
	//	static int noOfHosts = 1;

	static boolean verbose = false;
	static long lastRunTime = 0;

	static double maxDisk = 43400000;
	static int fixChangeTime=0;
	static double responseGoal=160;
	static double averageResponse=0;
	static double respStDev=0;
	static int totalIterations=0;
	static ArrayList<Double> RespTimes = new ArrayList<Double>();
	static ArrayList<VirtualMachine> VMs=new ArrayList<VirtualMachine>();
	static ArrayList<PhysicalMachine> PMs=new ArrayList<PhysicalMachine>();
	static ArrayList<Application> apps=new ArrayList<Application>();

	static boolean useInputController=false;
	static int numinputs=36;
	static double[] metricsToSend=new double[numinputs];
	//static double[] newAlloc=new double[numinputs];

	//static SearchSpace s = new SearchSpace();

	public static void main(String[] args) throws MatlabConnectionException, MatlabInvocationException {
		boolean foxControl=true;

		//	if (foxControl==true){
		RemoteMatlabProxyFactory factory = new RemoteMatlabProxyFactory();
		RemoteMatlabProxy matlab = factory.getProxy();
		try{Thread.sleep(5000);}
		catch(InterruptedException e){
			e.printStackTrace();
		}
		//	}

		PhysicalMachine amdw3=new PhysicalMachine("10.1.1.3","amdw3");
		PhysicalMachine amdw6=new PhysicalMachine("10.1.1.6","amdw6");
		PhysicalMachine amdw8=new PhysicalMachine("10.1.1.8","amdw8");

		Application tpcw1=new Application("tpcw1",500);
		Application vbench=new Application("vbench");

		VirtualMachine foxtpcwproxy=new VirtualMachine("foxtpcwproxy","hda",amdw6,tpcw1);
		VirtualMachine foxtpcwweb=new VirtualMachine("foxtpcwweb","vda",amdw3,tpcw1);
		VirtualMachine foxtpcwdb=new VirtualMachine("foxtpcwdb","hda",amdw8,tpcw1);
		foxtpcwproxy.setFirstTier();

		VirtualMachine vbenchfox1=new VirtualMachine("vbenchfox1","vda",amdw6,vbench);
		VirtualMachine vbenchfox2=new VirtualMachine("vbenchfox2","vda",amdw3,vbench);
		VirtualMachine vbenchfox3=new VirtualMachine("vbenchfox3","vda",amdw8,vbench);


		//	Application a = new Application(150);
		int[] sharePercent = {33,33,33};
		int[] previousShares = sharePercent;

		//if (foxControl==true){
		// Variable Initializations
		for (Application app:apps){
			if (app.hasSLA()==true){
				matlab.setVariable("numinputs"+app.getAppName(),numinputs);
				matlab.setVariable("phi"+app.getAppName(),0);
				matlab.eval("phi"+app.getAppName()+"=zeros(1,numinputs"+app.getAppName()+")';");
				matlab.setVariable("theta"+app.getAppName(),0);
				matlab.setVariable("newAllocOld"+app.getAppName(),0);
				matlab.eval("newAllocOld"+app.getAppName()+"=zeros(1,6)';");
				matlab.eval("theta"+app.getAppName()+"=zeros(1,numinputs"+app.getAppName()+")';");
				matlab.setVariable("P"+app.getAppName(),0);
				matlab.eval("P"+app.getAppName()+"=eye(numinputs"+app.getAppName()+")*1E-1;");
				matlab.setVariable("lambda",(double)24/(double)25);
				matlab.setVariable("K"+app.getAppName(),0);
				matlab.eval("K"+app.getAppName()+"=zeros(1,numinputs"+app.getAppName()+")';");
				matlab.setVariable("y"+app.getAppName(),0);
				matlab.setVariable("R"+app.getAppName(), 0);
				matlab.eval("R"+app.getAppName()+"=eye(numinputs"+app.getAppName()+");");
				matlab.setVariable("maxVal"+app.getAppName(),0);
				matlab.eval("maxVal"+app.getAppName()+"=ones(numinputs"+app.getAppName()+",1);");
				matlab.eval("maxVal"+app.getAppName()+"(1:6)=2;");
				matlab.setVariable("minMem"+app.getAppName(),0);
				matlab.eval("minMem"+app.getAppName()+"=ones(6,1)*1E50;");
				matlab.setVariable("memoryMetrics"+app.getAppName(),0);
				matlab.setVariable("RT"+app.getAppName(),0);
				matlab.setVariable("counter",1);
				matlab.setVariable("q",0.05);
				matlab.setVariable("newAlloc"+app.getAppName(),0);
				matlab.eval("newAlloc"+app.getAppName()+"=zeros(6,1);");
				matlab.setVariable("B",0);
				matlab.eval("B=[eye(6) zeros(6,numinputs"+app.getAppName()+"-6)];");
				matlab.setVariable("actualAlloc"+app.getAppName(),0);
			}
		}
		//	}
		try{	


			boolean changeShare=false;


			while(true){
				waitForReadings();
				for (Application app:apps){
					if (app.hasSLA()){
						for(VirtualMachine VM:app.getVMs()){
							if (VM.isFirstTier()==true){
								System.out.println("\n\nRT: " + VM.getMetric().getResponse_average());

								if (VM.getMetric().getResponse_average()<1500){
									RespTimes.add(VM.getMetric().getResponse_average());
									for (int k=0;k<RespTimes.size();k++)
										averageResponse+=RespTimes.get(k)/((double)RespTimes.size());
									for (int k=0;k<RespTimes.size();k++)
										respStDev+=Math.pow((RespTimes.get(k)-averageResponse),2)/((double)RespTimes.size());
									System.out.println("Average Response: "+averageResponse);
									System.out.println("Standard Deviation: "+Math.sqrt(respStDev));
									averageResponse=0;
									respStDev=0;
								}
							}
						}
					}
				}

				// CHANGE THIS NUMBER!
				int testNumber=29;
				for (Application app:apps){
					if (app.hasSLA()){
						outputMetrics(testNumber,app.getVMs(),app.getAppName());
					}
				}


				// BEGIN CONTROL
				//	if (foxControl==true){
				long matlabTime=new Date().getTime();
				for (Application app:apps){
					if (app.hasSLA()==true){
						metricsToSend=assignMetrics(app.getVMs(),numinputs);
						matlab.eval("phiOld"+app.getAppName()+"=phi"+app.getAppName()+";");
						matlab.eval("phi"+app.getAppName()+"=["+doubleArrayToString(metricsToSend)+"]';");
						for(VirtualMachine VM:app.getVMs())
							if (VM.isFirstTier()==true)
								matlab.eval("y"+app.getAppName()+"="+VM.getMetric().getResponse_average()+";");
						// normalizations
						matlab.eval("y"+app.getAppName()+"=y"+app.getAppName()+"/"+app.getRTTarget()+";");
						matlab.eval("memoryMetrics"+app.getAppName()+"=phi"+app.getAppName()+"(numinputs"+app.getAppName()+"-5:numinputs"+app.getAppName()+");");
						matlab.eval("minMem"+app.getAppName()+"(memoryMetrics"+app.getAppName()+"<minMem"+app.getAppName()+")=memoryMetrics"+app.getAppName()+"(memoryMetrics"+app.getAppName()+"<minMem"+app.getAppName()+");");
						matlab.eval("phi"+app.getAppName()+"(numinputs"+app.getAppName()+"-5:numinputs"+app.getAppName()+")=phi"+app.getAppName()+"(numinputs"+app.getAppName()+"-5:numinputs"+app.getAppName()+")-minMem"+app.getAppName()+";");
						matlab.eval("maxVal"+app.getAppName()+"(phi"+app.getAppName()+">maxVal"+app.getAppName()+")=phi"+app.getAppName()+"(phi"+app.getAppName()+">maxVal"+app.getAppName()+");");
						matlab.eval("phi"+app.getAppName()+"=phi"+app.getAppName()+"./maxVal"+app.getAppName()+";");
						// estimation
						matlab.eval("[theta"+app.getAppName()+",P"+app.getAppName()+",K"+app.getAppName()+",R"+app.getAppName()+"]=estimator(lambda,numinputs"+app.getAppName()+",R"+app.getAppName()+",phi"+app.getAppName()+",theta"+app.getAppName()+",P"+app.getAppName()+",y"+app.getAppName()+");");
						matlab.eval("RT"+app.getAppName()+"(counter)=phi"+app.getAppName()+"'*theta"+app.getAppName()+"*"+app.getRTTarget()+";");
						//				matlab.eval("newAlloc=(theta*theta'+q*eye(numinputs))^(-1)*(1*theta+q*phiOld)");
						//				matlab.eval("newAlloc=newAlloc.*maxVal;");
						//				matlab.eval("newAlloc(numinputs-5:numinputs)=newAlloc(numinputs-5:numinputs)+minMem;");
						matlab.eval("newAlloc"+app.getAppName()+"=(pinv(B)'*theta"+app.getAppName()+"*theta"+app.getAppName()+"'*pinv(B)+q*eye(6))^(-1)*(1*pinv(B)'*theta"+app.getAppName()+"+q*newAllocOld"+app.getAppName()+")");
						matlab.eval("newAlloc"+app.getAppName()+"=newAlloc"+app.getAppName()+".*maxVal"+app.getAppName()+"(1:6);");
						matlab.eval("actualAlloc"+app.getAppName()+"=newAlloc"+app.getAppName()+"./(1+newAlloc"+app.getAppName()+");");
						//	matlab.eval("newAlloc(numinputs-5:numinputs)=newAlloc(numinputs-5:numinputs)+minMem;");
						double[] coeffs=(double[])matlab.getVariable("theta"+app.getAppName());
						double[] newAlloc=(double[])matlab.getVariable("actualAlloc"+app.getAppName());
						for (int i=0;i<app.getVMs().size();i++)
							app.getVMs().get(i).setCPUReq(newAlloc[i]);
						for (int i=app.getVMs().size();i<2*app.getVMs().size();i++)
							app.getVMs().get(i-app.getVMs().size()).setCPUIFReq(newAlloc[i]);

						outputCoeffs(coeffs,testNumber,app.getAppName());
						System.out.println(newAlloc[0]+", "+newAlloc[1]+", "+newAlloc[2]+", "+newAlloc[3]+", "+newAlloc[4]+", "+newAlloc[5]);

					}
				}
				matlab.eval("counter=counter+1;");
				System.out.println(new Date().getTime()-matlabTime);

				double[] counter=(double[])matlab.getVariable("counter");
				System.out.println("counter: "+counter[0]);
				if (counter[0]>40){
					for (PhysicalMachine PM:PMs){
						PM.assignCPU();
					}
				}

				changeShare=false;

				if(changeShare && metrics[0].getResponse_average()<1500){
					//a.addReading(readings);

					// Change the share value
					//ShareModel sm = a.getCurrentShareModel();
					//ShareModelMinShareOptimize op = sm.getOptimizer();

					//int[] shares = a.getMinShares();
					//int[] shares = s.getMinShares();
					int[] shares = previousShares;
					double beta=0.3;

					//					if (metrics[0].getResponse_average()-responseGoal>0)
					//						beta=0.05;

					shares[0]+=beta*((double)metrics[0].getResponse_average()-(double)responseGoal);
					shares[1]+=beta*((double)metrics[0].getResponse_average()-(double)responseGoal)/3;
					previousShares = shares;

					for(int share:shares)
						System.out.println("share: " + share);

					//openURL("http://"+hosts[0]+":9111/vcontrol/vm/"+VMNames[0]+"/cpu/share/"+shares[0]*10);
					//openURL("http://"+hosts[1]+":9111/vcontrol/vm/"+VMNames[1]+"/cpu/share/"+shares[1]*10);

					//if(fixChangeTime>4){
					//	for (int i=0;i<noOfVMs;i++){
					//		openURL("http://"+hosts[i]+":9111/vcontrol/vm/"+VMNames[i]+"/cpu/share/"+shares[i]*10);
					//	}

					//fixChangeTime=0;
					//}
					//else fixChangeTime++;
				}

				if (useInputController==true){
					for (VirtualMachine VM:VMs){
						if (VM.useInputController()==true){
							openURL("http://10.22.0.1:33450/index.html?backend=GALAXY&server="+VM.getHostFakeName()+"&weight="+VM.getMetric().getInputControllerWeight());
						}
					}
				}

			}
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}

	/**
	 * Waits for the new metric readings to come in from all of the VMs
	 * @throws IOException 
	 * @throws MalformedURLException 
	 * @throws JsonMappingException 
	 * @throws JsonParseException 
	 */
	private static void waitForReadings() throws JsonParseException, JsonMappingException, MalformedURLException, IOException{
		// Set the new metrics we have to null

		for(VirtualMachine VM:VMs) VM.nullNewMetric();
		boolean allDifferent = false;

		while(!allDifferent){

			if(verbose) System.out.println("waitForReading: checking for a new reading");
			// Sleep before we try to read again
			try{ sleep(500); }
			catch (InterruptedException e) {
				e.printStackTrace(); }

			// Set the time to look back over the previous 20 seconds
			long startTime = lastRunTime - 10000;
			lastRunTime = new Date().getTime();

			// Try to get the new metric readings (and make sure it's not just the old one)
			//for(int i=0; i<noOfVMs; i++){
			for (Application app:apps){
				if (app.hasSLA()==true){
					for(VirtualMachine VM:app.getVMs()){

						//if(newMetrics[i] == null || newMetrics[i].equals(metrics[i])){
						VM.setNewMetric(getLatestMetric(VM.getPM().getHostIP(),VM.getVMName()));

						if (VM.getNewMetric()!=null){
							getMonitorMetrics(VM);
						}
					}
				}
				//}
			}

			// If all of the metrics are different we can exit
			allDifferent = true;
			for (Application app:apps){
				if (app.hasSLA()==true){
					for(VirtualMachine VM:app.getVMs()){
						//if(newMetrics[i] == null || newMetrics[i].equals(metrics[i])){
						boolean condition=false;

						if (VM.getNewMetric()!=null&&VM.getMetric()!=null){
							//condition=(newMetrics[i].getEndtime().equals(metrics[i].getEndtime())||newMetrics[i].equals(metrics[i]));
							condition=VM.getNewMetric().getEndtime().equals(VM.getMetric().getEndtime());
							if(verbose)System.out.println(VM.getNewMetric().getEndtime()+"   "+VM.getMetric().getEndtime()+"    "+VM.getNewMetric().getEndtime().equals(VM.getMetric().getEndtime())+"     "+VM.getNewMetric().equals(VM.getMetric())+"     "+condition);
						}
						if(VM.getNewMetric() == null || condition){	
							allDifferent = false;
							if(verbose) System.out.println("waitForReading: A metric is the same");
						}
					}
				}
			}
			//System.out.println(lastRunTime);
			//System.out.println(startTime);
		}

		// Just get the latest metrics, as we may have skipped a reading as sometimes they don't report
		for (Application app:apps){
			if (app.hasSLA()==true){
				for(VirtualMachine VM:app.getVMs()){
					VM.setNewMetric(getLatestMetric(VM.getPM().getHostIP(),VM.getVMName()));
					//openURL("http://"+hosts[i]+":9111/vcontrol/metric/collect?app=tpcw&vm="+VMNames[i]+"&host="+hosts[i]+"&response_average="+newMetrics[i].getResponse_average()+"&time="+(newMetrics[i].getTime())+"&endtime="+newMetrics[i].getEndtime());
					//System.out.println("http://"+hosts[i]+":9111/vcontrol/metric/collect?app=tpcw&vm="+VMNames[i]+"&host="+hosts[i]+"&response_average="+newMetrics[i].getResponse_average()+"&time="+(newMetrics[i].getTime())+"&endtime="+newMetrics[i].getEndtime());
					if (VM.getNewMetric()!=null){
						getMonitorMetrics(VM);
					}
				}
			}
		}


		if(verbose) System.out.println("waitForReading: Got all different metrics");
		if(verbose){
			for (Application app:apps){
				if (app.hasSLA()==true){
					for(VirtualMachine VM:app.getVMs()){
						Metric m=VM.getNewMetric();
						System.out.println("waitForReading: " + m);
					}
				}
			}
		}

		for (Application app:apps)
			if (app.hasSLA()==true)
				for(VirtualMachine VM:app.getVMs())
					VM.newMetricToMetric();
	}

	/**
	 * Get the last metric reported by a host
	 */
	private static Metric getLatestMetric(String host, String VMname){
		long startTime = lastRunTime - 10000;
		lastRunTime = new Date().getTime();
		Metric ret=null;

		String urlString = "http://" + host + ":9111/vcontrol/metric/get?time="+(lastRunTime-20000)+"&endtime="+lastRunTime+"&vm="+VMname;
		if(verbose) System.out.println(urlString);
		// Get the utilization levels and response time for the previous time period
		ObjectMapper mapper = new ObjectMapper();
		Metric[] metrics = null;

		try{
			metrics = mapper.readValue(new URL(urlString), Metric[].class);
		}
		catch(Exception e){
			e.printStackTrace();
		}

		if(metrics != null && metrics.length > 0)
			ret = metrics[metrics.length-1];

		return ret;
	}

	private static void getMonitorMetrics(VirtualMachine VM) throws JsonParseException, JsonMappingException, MalformedURLException, IOException{
		ObjectMapper mapper = new ObjectMapper();
		// VM CPU
		JsonNode nodeVM = mapper.readValue(new URL("http://monitor:5100/list/vcpu/"+VM.getVMName()+"/points?last=10"), JsonNode.class);
		VM.getNewMetric().setUtil_cpu(nodeVM.get("series").get("vcpu:percent").get(nodeVM.get("series").get("vcpu:percent").size()-1).getDoubleValue());	
		// PM CPU
		JsonNode nodeHost=mapper.readValue(new URL("http://monitor:5100/list/cpu/"+VM.getPM().getHostName()+".arcanine.lan/0/cpu/active/points?last=10"), JsonNode.class);
		VM.getNewMetric().setPMActiveCPU(nodeHost.get("series").get("active:percent").get(nodeHost.get("series").get("active:percent").size()-1).getDoubleValue());
		nodeHost=mapper.readValue(new URL("http://monitor:5100/list/cpu/"+VM.getPM().getHostName()+".arcanine.lan/0/cpu/steal/points?last=10"), JsonNode.class);
		VM.getNewMetric().setPMStealCPU(nodeHost.get("series").get("steal:value").get(nodeHost.get("series").get("steal:value").size()-1).getDoubleValue());
		nodeHost=mapper.readValue(new URL("http://monitor:5100/list/cpu/"+VM.getPM().getHostName()+".arcanine.lan/0/cpu/wait/points?last=10"), JsonNode.class);
		VM.getNewMetric().setPMWaitCPU(nodeHost.get("series").get("wait:value").get(nodeHost.get("series").get("wait:value").size()-1).getDoubleValue());
		// NET
		JsonNode nodeVMnet = mapper.readValue(new URL("http://monitor:5100/list/libvirt/"+VM.getVMName()+"/null/if_packets/"+VM.getVnet()+"/points?last=10"), JsonNode.class);
		VM.getNewMetric().setVM_net_packRx(nodeVMnet.get("series").get(VM.getVnet()+":rx").get(nodeVMnet.get("series").get(VM.getVnet()+":rx").size()-1).getDoubleValue());
		VM.getNewMetric().setVM_net_packTx(nodeVMnet.get("series").get(VM.getVnet()+":tx").get(nodeVMnet.get("series").get(VM.getVnet()+":tx").size()-1).getDoubleValue());
		nodeVMnet = mapper.readValue(new URL("http://monitor:5100/list/libvirt/"+VM.getVMName()+"/null/if_octets/"+VM.getVnet()+"/points?last=10"), JsonNode.class);
		//System.out.println(VM.getVMName());
		VM.getNewMetric().setVM_net_ByteRx(nodeVMnet.get("series").get(VM.getVnet()+":rx").get(nodeVMnet.get("series").get(VM.getVnet()+":rx").size()-1).getDoubleValue());
		VM.getNewMetric().setVM_net_ByteTx(nodeVMnet.get("series").get(VM.getVnet()+":tx").get(nodeVMnet.get("series").get(VM.getVnet()+":tx").size()-1).getDoubleValue());
		// NETIF (wrong)
		// JsonNode nodeHostnet=mapper.readValue(new URL("http://monitor:5100/list/interface/"+hostName[i]+".arcanine.lan/virbr1/if_octets/null/points?last=10"), JsonNode.class);
		// VM.getNewMetric().setIf_net(nodeHostnet.get("series").get(":rx").get(nodeHostnet.get("series").get(":rx").size()-1).getDoubleValue()+nodeHostnet.get("series").get(":tx").get(nodeHostnet.get("series").get(":tx").size()-1).getDoubleValue()-newMetrics[i].getUtil_net());
		// DISK
		JsonNode nodeVMdisk = mapper.readValue(new URL("http://monitor:5100/list/libvirt/"+VM.getVMName()+"/null/disk_ops/"+VM.getDiskName()+"/points?last=10"), JsonNode.class);
		VM.getNewMetric().setVM_disk_opsRead(nodeVMdisk.get("series").get(VM.getDiskName()+":read").get(nodeVMdisk.get("series").get(VM.getDiskName()+":read").size()-1).getDoubleValue());
		VM.getNewMetric().setVM_disk_opsWrite(nodeVMdisk.get("series").get(VM.getDiskName()+":write").get(nodeVMdisk.get("series").get(VM.getDiskName()+":write").size()-1).getDoubleValue());
		nodeVMdisk = mapper.readValue(new URL("http://monitor:5100/list/libvirt/"+VM.getVMName()+"/null/disk_octets/"+VM.getDiskName()+"/points?last=10"), JsonNode.class);
		VM.getNewMetric().setVM_disk_ByteRead(nodeVMdisk.get("series").get(VM.getDiskName()+":read").get(nodeVMdisk.get("series").get(VM.getDiskName()+":read").size()-1).getDoubleValue());
		VM.getNewMetric().setVM_disk_ByteWrite(nodeVMdisk.get("series").get(VM.getDiskName()+":write").get(nodeVMdisk.get("series").get(VM.getDiskName()+":write").size()-1).getDoubleValue());
		// memory
		JsonNode nodeHostMem=mapper.readValue(new URL("http://monitor:5100/list/memory/"+VM.getPM().getHostName()+".arcanine.lan/null/memory/usage/points?last=10"), JsonNode.class);
		VM.getNewMetric().setUsed_mem(nodeHostMem.get("series").get("used").get(nodeHostMem.get("series").get("used").size()-1).getDoubleValue());
		VM.getNewMetric().setCached_mem(nodeHostMem.get("series").get("cached").get(nodeHostMem.get("series").get("cached").size()-1).getDoubleValue());
		VM.getNewMetric().setBuffered_mem(nodeHostMem.get("series").get("buffered").get(nodeHostMem.get("series").get("buffered").size()-1).getDoubleValue());
		VM.getNewMetric().setFree_mem(nodeHostMem.get("series").get("free").get(nodeHostMem.get("series").get("free").size()-1).getDoubleValue());
	}

	private static String openURL(String urlString){
		String ret = null;

		try{
			URL url = new URL(urlString);
			BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));

			ret = br.readLine();
		}
		catch(Exception e){
			e.printStackTrace();
		}

		return ret;
	}

	public static void addVM(VirtualMachine newVM){
		VMs.add(newVM);
	}

	public static void addPM(PhysicalMachine newPM){
		PMs.add(newPM);
	}

	public static void addApp(Application newApp){
		apps.add(newApp);
	}

	public static void outputMetrics(int testNumber,ArrayList<VirtualMachine> VMs, String appName) throws IOException{
		FileWriter fstream = new FileWriter("C:\\Users\\afox1\\Documents\\VM Work\\TestRuns\\test_"+testNumber+"_"+appName+".csv",true);
		BufferedWriter out = new BufferedWriter(fstream);

		// Write util values
		for(VirtualMachine VM:VMs){
			//		if(VM.isControl()==true)
			out.write(VM.getMetric().getUtil_cpu()+",");
		}
		for(VirtualMachine VM:VMs){
			//		if(VM.isControl()==true)
			out.write(VM.getMetric().getVM_net_packTx()+",");
		}
		for(VirtualMachine VM:VMs){
			//			if(VM.isControl()==true)
			out.write(VM.getMetric().getVM_net_packRx()+",");
		}
		for(VirtualMachine VM:VMs){
			//			if(VM.isControl()==true)
			out.write(VM.getMetric().getVM_net_ByteTx()+",");
		}
		for(VirtualMachine VM:VMs){
			//			if(VM.isControl()==true)
			out.write(VM.getMetric().getVM_net_ByteRx()+",");
		}
		for(VirtualMachine VM:VMs){
			//			if(VM.isControl()==true)
			out.write(VM.getMetric().getVM_disk_opsRead()+",");
		}
		for(VirtualMachine VM:VMs){
			//			if(VM.isControl()==true)
			out.write(VM.getMetric().getVM_disk_opsWrite()+",");
		}
		for(VirtualMachine VM:VMs){
			//			if(VM.isControl()==true)
			out.write(VM.getMetric().getVM_disk_ByteRead()+",");
		}
		for(VirtualMachine VM:VMs){
			//			if(VM.isControl()==true)
			out.write(VM.getMetric().getVM_disk_ByteWrite()+",");
		}
		for(VirtualMachine VM:VMs){
			//			if(VM.isControl()==true)
			out.write(VM.getMetric().getUtil_storage()/(maxDisk/100)+",");
		}
		for(VirtualMachine VM:VMs){
			//			if(VM.isControl()==true)
			out.write(VM.getMetric().getIf_cpu()+",");
		}
		for(VirtualMachine VM:VMs){
			//		if(VM.isControl()==true)
			out.write(VM.getMetric().getIf_net()+",");
		}
		for(VirtualMachine VM:VMs){
			//		if(VM.isControl()==true)
			out.write(VM.getMetric().getIf_storage()/(maxDisk/100)+",");
		}
		for(VirtualMachine VM:VMs){
			//			if(VM.isControl()==true)
			out.write(VM.getMetric().getIf_ram()+",");
		}
		for(VirtualMachine VM:VMs){
			//			if(VM.isControl()==true)
			if (VM.isFirstTier()==true)
				out.write(VM.getMetric().getResponse_average()+",");
		}
		for(VirtualMachine VM:VMs){
			//			if(VM.isControl()==true)
			out.write(VM.getMetric().getShare_cpu()+",");
		}
		for(VirtualMachine VM:VMs){
			//			if(VM.isControl()==true)
			out.write(VM.getMetric().getUsed_mem()+",");
		}
		for(VirtualMachine VM:VMs){
			//			if(VM.isControl()==true)
			out.write(VM.getMetric().getCached_mem()+",");
		}
		for(VirtualMachine VM:VMs){
			//			if(VM.isControl()==true)
			out.write(VM.getMetric().getBuffered_mem()+",");
		}
		for(VirtualMachine VM:VMs){
			//			if(VM.isControl()==true)
			out.write(VM.getMetric().getFree_mem()+",");
		}
		for(VirtualMachine VM:VMs){
			//			if(VM.isControl()==true)
			out.write(VM.getMetric().getPMActiveCPU()+",");
		}
		for(VirtualMachine VM:VMs){
			//			if(VM.isControl()==true)
			out.write(VM.getMetric().getPMStealCPU()+",");
		}
		for(VirtualMachine VM:VMs){
			//			if(VM.isControl()==true)
			out.write(VM.getMetric().getPMWaitCPU()+",");
		}
		out.newLine();
		out.close();
	}

	/**
	 * Converts the array of doubles to a string with commas inseted between values
	 * @param oldArray Array of doubles
	 * @return String of values with commas inserted
	 */
	public static String doubleArrayToString(double[] oldArray){
		String newString="";
		for(int i=0;i<oldArray.length;i++)
			newString+=Double.toString(oldArray[i])+",";
		return newString;
	}

	/**
	 * Places the desired metrics for estimation and control into an array of doubles
	 * @param VMs All the virtual machines
	 * @param numinputs The number of metrics used
	 * @return array of the metrics to be sent to matlab
	 */
	public static double[] assignMetrics(ArrayList<VirtualMachine>VMs,int numinputs){
		double[] metricsToSend=new double[numinputs];
		int numControlVMs=0;
		for(VirtualMachine VM:VMs){
			numControlVMs++;
		}
		for(int i=0;i<(numinputs/numControlVMs);i++){
			int j=0;
			for(VirtualMachine VM:VMs){
				if(i==0)
					metricsToSend[i*numControlVMs+j]=(VM.getMetric().getUtil_cpu()/100)/(1-(VM.getMetric().getUtil_cpu()/100));
				if(i==1)
					metricsToSend[i*numControlVMs+j]=(VM.getMetric().getIf_cpu()/100)/(1-(VM.getMetric().getIf_cpu()/100));
				if(i==2)
					metricsToSend[i*numControlVMs+j]=VM.getMetric().getVM_net_packRx();
				if(i==3)
					metricsToSend[i*numControlVMs+j]=VM.getMetric().getVM_net_packTx();
				if(i==4)
					metricsToSend[i*numControlVMs+j]=VM.getMetric().getVM_net_ByteRx();
				if(i==5)
					metricsToSend[i*numControlVMs+j]=VM.getMetric().getVM_net_ByteTx();
				if(i==6)
					metricsToSend[i*numControlVMs+j]=VM.getMetric().getVM_disk_opsRead();
				if(i==7)
					metricsToSend[i*numControlVMs+j]=VM.getMetric().getVM_disk_opsWrite();
				if(i==8)
					metricsToSend[i*numControlVMs+j]=VM.getMetric().getVM_disk_ByteRead();
				if(i==9)
					metricsToSend[i*numControlVMs+j]=VM.getMetric().getVM_disk_ByteWrite();
				if(i==10)
					metricsToSend[i*numControlVMs+j]=VM.getMetric().getUsed_mem();
				if(i==11)
					metricsToSend[i*numControlVMs+j]=VM.getMetric().getCached_mem();
				j++;
			}
		}
		return metricsToSend;
	}

	/**
	 * Takes the coefficients returned from matlab and outputs them to a csv file
	 * @param coeffs	The coefficients from matlab
	 * @param testNumber	Test Run number used to index csv files
	 * @throws IOException
	 */
	public static void outputCoeffs(double[] coeffs,int testNumber, String appName) throws IOException{
		FileWriter fstreamC = new FileWriter("C:\\Users\\afox1\\Documents\\VM Work\\TestRuns\\coeff_"+testNumber+"_"+appName+".csv",true);
		BufferedWriter out = new BufferedWriter(fstreamC);
		for(int i=0;i<coeffs.length;i++){
			out.write(coeffs[i]+",");
		}	
		out.newLine();
		out.close();
	}
}
